module gpumath.vector;
import std.math;

struct vec2t(T){
	union{
		T[2] m;
		struct{
			T x,y;
		}
	}
	
	this(T x, T y){
		this.x = x;
		this.y = y;
	}
	
	vec2t opBinary(string op)( const ref vec2t r ) const if( op == "+" || op =="-" || op=="*" || op=="/" ){
		return mixin(typeof(this).stringof~"(x"~op~"r.x, y"~op~"r.y)");
	}
	
	vec2t opBinary(string op)( T r ) const if( op == "+" || op =="-" || op=="*" || op=="/" ){
		return mixin(typeof(this).stringof~"(x"~op~"r, y"~op~"r)");
	}
}

struct vec3t(T){
	union{
		T[3] m;
		struct{
			T x,y,z;
		}
	}
	
	this(T x, T y, T z){
		this.x = x;
		this.y = y;
		this.z = z;
	}
	
	vec3t opBinary(string op)( const ref vec3t r ) const if( op == "+" || op =="-" || op=="*" || op=="/" ){
		return mixin(typeof(this).stringof~"(x"~op~"r.x, y"~op~"r.y, z"~op~"r.z)");
	}
	
	vec3t opBinary(string op)( T r ) const if( op == "+" || op =="-" || op=="*" || op=="/" ){
		return mixin(typeof(this).stringof~"(x"~op~"r, y"~op~"r, z"~op~"r)");
	}
}


struct vec4t(T){
	union{
		T[4] m;
		struct{
			T x,y,z,w;
		}
	}
	
	this(T x, T y, T z, T w){
		this.x = x;
		this.y = y;
		this.z = z;
		this.w = w;
	}
	
	vec4t opBinary(string op)( const ref vec4t r ) const if( op == "+" || op =="-" || op=="*" || op=="/" ){
		return mixin(typeof(this).stringof~"(x"~op~"r.x, y"~op~"r.y, z"~op~"r.z, w"~op~"r.w)");
	}
	
	vec4t opBinary(string op)( T r ) const if( op == "+" || op =="-" || op=="*" || op=="/" ){
		return mixin(typeof(this).stringof~"(x"~op~"r, y"~op~"r, z"~op~"r, w"~op~"r)");
	}
}

alias vec2t!float vec2f;
alias vec2f vec2;

alias vec3t!float vec3f;
alias vec3f vec3;

alias vec4t!float vec4f;
alias vec4f vec4;

T dot(T)( const ref vec2t!T u, const ref vec2t!T v ){
	return
		u.x*v.x +
		u.y*v.y;
}

T dot(T)( const ref vec3t!T u, const ref vec3t!T v ){
	return
		u.x*v.x +
		u.y*v.y +
		u.z*v.z;
}


T dot(T)( const ref vec4t!T u, const ref vec4t!T v ){
	return
		u.x*v.x +
		u.y*v.y +
		u.z*v.z +
		u.w*v.w;
}


vec3t!T cross(T)( const ref vec3t!T u, const ref vec3t!T v ){
	return 
		vec3t!T(
			u.y*v.z-u.z*v.y,
			u.z*v.x-u.x*v.z,
			u.x*v.y-u.y*v.x);
}

T length(T)( const ref vec2t!T u ){
	return sqrt( u.x*u.x + u.y*u.y );
}

T length(T)( const ref vec3t!T u ){
	return sqrt( u.x*u.x + u.y*u.y + u.z*u.z );
}

T length(T)( const ref vec4t!T u ){
	return sqrt( u.x*u.x + u.y*u.y + u.z*u.z + u.w*u.w);
}

vec2t!T normalize(T)( const ref vec2t!T u){
	T rlen = 1/length(u);
	return u*rlen;
}

vec3t!T normalize(T)( const ref vec3t!T u){
	T rlen = 1/length(u);
	return u*rlen;
}

vec4t!T normalize(T)( const ref vec4t!T u){
	T rlen = 1/length(u);
	return u*rlen;
}